1   /*
2    * Copyright (C) 2010 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.testing;
18  
19  import com.google.common.annotations.GwtCompatible;
20  
21  import junit.framework.TestCase;
22  
23  /**
24   * @author Luiz-Otavio "Z" Zorzella
25   */
26  @GwtCompatible
27  public class TearDownStackTest extends TestCase {
28  
29    private TearDownStack tearDownStack = new TearDownStack();
30  
31    public void testSingleTearDown() throws Exception {
32      final TearDownStack stack = buildTearDownStack();
33  
34      final SimpleTearDown tearDown = new SimpleTearDown();
35      stack.addTearDown(tearDown);
36  
37      assertEquals(false, tearDown.ran);
38  
39      stack.runTearDown();
40  
41      assertEquals("tearDown should have run", true, tearDown.ran);
42    }
43  
44    public void testMultipleTearDownsHappenInOrder() throws Exception {
45      final TearDownStack stack = buildTearDownStack();
46  
47      final SimpleTearDown tearDownOne = new SimpleTearDown();
48      stack.addTearDown(tearDownOne);
49  
50      final Callback callback = new Callback() {
51        @Override
52        public void run() {
53          assertEquals("tearDownTwo should have been run before tearDownOne",
54            false, tearDownOne.ran);
55        }
56      };
57  
58      final SimpleTearDown tearDownTwo = new SimpleTearDown(callback);
59      stack.addTearDown(tearDownTwo);
60  
61      assertEquals(false, tearDownOne.ran);
62      assertEquals(false, tearDownTwo.ran);
63  
64      stack.runTearDown();
65  
66      assertEquals("tearDownOne should have run", true, tearDownOne.ran);
67      assertEquals("tearDownTwo should have run", true, tearDownTwo.ran);
68    }
69  
70    public void testThrowingTearDown() throws Exception {
71      final TearDownStack stack = buildTearDownStack();
72  
73      final ThrowingTearDown tearDownOne = new ThrowingTearDown("one");
74      stack.addTearDown(tearDownOne);
75  
76      final ThrowingTearDown tearDownTwo = new ThrowingTearDown("two");
77      stack.addTearDown(tearDownTwo);
78  
79      assertEquals(false, tearDownOne.ran);
80      assertEquals(false, tearDownTwo.ran);
81  
82      try {
83        stack.runTearDown();
84        fail("runTearDown should have thrown an exception");
85      } catch (ClusterException expected) {
86        assertEquals("two", expected.getCause().getMessage());
87      } catch (RuntimeException e) {
88        throw new RuntimeException(
89          "A ClusterException should have been thrown, rather than a " + e.getClass().getName(), e);
90      }
91  
92      assertEquals(true, tearDownOne.ran);
93      assertEquals(true, tearDownTwo.ran);
94    }
95  
96    @Override public final void runBare() throws Throwable {
97      try {
98        setUp();
99        runTest();
100     } finally {
101       tearDown();
102     }
103   }
104 
105   @Override protected void tearDown() {
106     tearDownStack.runTearDown();
107   }
108 
109   /**
110    * Builds a {@link TearDownStack} that makes sure it's clear by the end of
111    * this test.
112    */
113   private TearDownStack buildTearDownStack() {
114     final TearDownStack result = new TearDownStack();
115     tearDownStack.addTearDown(new TearDown() {
116 
117       @Override
118       public void tearDown() throws Exception {
119         assertEquals(
120           "The test should have cleared the stack (say, by virtue of running runTearDown)",
121           0, result.stack.size());
122       }
123     });
124     return result;
125   }
126 
127   private static final class ThrowingTearDown implements TearDown {
128 
129     private final String id;
130     boolean ran = false;
131 
132     ThrowingTearDown(String id) {
133       this.id = id;
134     }
135 
136     @Override
137     public void tearDown() throws Exception {
138       ran = true;
139       throw new RuntimeException(id);
140     }
141   }
142 
143   private static final class SimpleTearDown implements TearDown {
144 
145     boolean ran = false;
146     Callback callback = null;
147 
148     public SimpleTearDown() {}
149 
150     public SimpleTearDown(Callback callback) {
151       this.callback = callback;
152     }
153 
154     @Override
155     public void tearDown() throws Exception {
156       if (callback != null) {
157         callback.run();
158       }
159       ran = true;
160     }
161   }
162 
163   private interface Callback {
164     void run();
165   }
166 }